package com.sfj.common.util;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

/**
 * @author kaka
 * @Date 2025/5/1
 */
public class Reflect {


    public static <T> T newT(Class<T> cls, Class<?>[] parameterTypes, Object[] parameters) throws Exception {
        Constructor<T> cons = cls.getDeclaredConstructor(parameterTypes);

        cons.setAccessible(true);
        return cons.newInstance(parameters);
    }

    public static Object newT(String clsStr, Class<?>[] parameterTypes, Object[] parameters) throws Exception {
        Class cls = Class.forName(clsStr);
        Constructor cons = cls.getDeclaredConstructor(parameterTypes);
        cons.setAccessible(true);
        return cons.newInstance(parameters);
    }


    /**
     * 获取对象的变量值
     *
     * @param obj       指定对象
     * @param fieldName 指定属性名称
     * @return 指定属性
     */
    public static Object getFieldValue(Object obj, String fieldName) {
        Field field = Reflect.getField(obj, fieldName);
        if (field != null) {
            field.setAccessible(true);
            try {
                return field.get(obj);
            } catch (Exception e) {

            }
        }
        return null;
    }

    /**
     * 获取对象的Field值
     *
     * @param obj   指定对象
     * @param field 指定属性名称
     * @return 指定属性
     */
    public static Object getFieldValue(Object obj, Field field) {
        if (field != null) {
            field.setAccessible(true);
            try {
                return field.get(obj);
            } catch (Exception e) {
            }
        }
        return null;
    }

    /**
     * 获取对象变量的Fileid
     *
     * @param obj       目标对象
     * @param fieldName 指定属性名称
     * @return 属性对象
     */
    private static Field getField(Object obj, String fieldName) {
        for (Class<?> clazz = obj.getClass(); clazz != Object.class; clazz = clazz.getSuperclass()) {
            try {
                return clazz.getDeclaredField(fieldName);
            } catch (Exception e) {
                // do nothing
            }
        }
        return null;
    }

    /**
     * 设置指定对象的指定属性值
     *
     * @param obj        指定对象
     * @param fieldName  指定属性
     * @param fieldValue 指定属性值
     */
    public static void setFieldValue(Object obj, String fieldName, Object fieldValue) {
        Field field = Reflect.getField(obj, fieldName);
        if (field != null) {
            try {
                field.setAccessible(true);
                field.set(obj, fieldValue);
            } catch (Exception e) {
            }
        }
    }

    /**
     * 设置指定对象的指定属性值
     *
     * @param obj        指定对象
     * @param field      指定属性
     * @param fieldValue 指定属性值
     */
    public static void setFieldValue(Object obj, Field field, Object fieldValue) {
        if (field != null) {
            try {
                field.setAccessible(true);
                field.set(obj, fieldValue);
            } catch (Exception e) {
            }
        }
    }


    /**
     * 获取属性名数组
     */
    private static String[] getFiledName(Object o) {
        Class clazz = o.getClass();
        List<Field> fieldsList = new ArrayList<Field>();

        //TODO 缓存数组解析
        while (clazz != null) {
            Field[] declaredFields = clazz.getDeclaredFields();
            if (fieldsList.isEmpty()) {
                fieldsList = new ArrayList<Field>(Arrays.asList(declaredFields));
            } else {
                Collections.addAll(fieldsList, declaredFields);
            }
            clazz = clazz.getSuperclass();
        }
        String[] fieldNames = new String[fieldsList.size()];
        for (int i = 0; i < fieldsList.size(); i++) {
            fieldNames[i] = fieldsList.get(i).getName();
        }
        return fieldNames;
    }

    private static Object getFieldValueByName(String fieldName, Object o) {
        try {
            String firstLetter = fieldName.substring(0, 1).toUpperCase();
            String getter = "get" + firstLetter + fieldName.substring(1);
            Method method = o.getClass().getMethod(getter, new Class[]{});
            Object value = method.invoke(o, new Object[]{});
            return value;
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * 获取对象的所有属性值，返回一个对象数组
     */
    public static Object[] getFiledValues(Object o) {
        String[] fieldNames = getFiledName(o);
        Object[] value = new Object[fieldNames.length];
        for (int i = 0; i < fieldNames.length; i++) {
            value[i] = getFieldValueByName(fieldNames[i], o);
        }
        return value;
    }

    /**
     * @param source 源对象
     * @param target 复制到的对象
     * @return
     */
    public static <T> T copyMethods(Object source, Class<T> target) {
        T targetObj = null;
        try {
            targetObj = target.newInstance();
        } catch (Exception e1) {
            e1.printStackTrace();
        }
        copyMethods(source, targetObj);
        return targetObj;
    }

    /**
     * @param source 源对象
     * @param target 复制到的对象
     * @return
     */
    public static void copyMethods(Object source, Object target) {
        Method[] methods = source.getClass().getMethods();// 得到父类所有方法
        for (Method method : methods) {// 遍历父类方法
            try {
                if (method.getName().startsWith("get")) {// 得到父类的get方法
                    // 尝试得到子类的set方法 method.getReturnType()：即得到返回类
                    Method targetObjMethod = target.getClass().getMethod(method.getName().replaceFirst("get", "set"), method.getReturnType());

                    Object value = method.invoke(source);// 通过get方法得到父类的值
                    targetObjMethod.invoke(target, value);// 将父类的属性注入到子类里面去
                }
            } catch (Exception e) {
            }
        }
    }

    /**
     * @param source 源对象
     * @param target 复制到的对象
     * @return
     */
    public static void copyField(Object source, Object target) {
        Field[] fields = target.getClass().getFields();
        for (Field fieldTar : fields) {
            try {
                Field fieldSou = source.getClass().getField(fieldTar.getName());
                Object fieldValue = getFieldValue(source, fieldSou);
                setFieldValue(target, fieldTar, fieldValue);
            } catch (Exception e) {
            }
        }
    }


}

